package com.dhms.vostok1.model

import android.util.Log
import androidx.lifecycle.*
import com.dhms.uikit.select_bottom_sheet.SelectItem
import com.dhms.vostok1.data.ApiResult
import com.dhms.vostok1.data.ApiState
import com.dhms.vostok1.data.MockAbnormalRecords
import com.dhms.vostok1.data.spot_patrol.*
import com.dhms.vostok1.repository.SpcTaskRepository
import com.dhms.vostok1.service.net.NetworkApi
import kotlinx.coroutines.launch

enum class TaskGroupType {
    ALL, RELIEF, SPOT_PATROL
}

enum class TaskGroupStatus {
    UN_DONE, TIMEOUT, DONE, TODO
}

class SpotCheckViewModel : ViewModel() {
    private val _abnormalRecordListData = MutableLiveData<List<MockAbnormalRecords?>?>(listOf())
    val abnormalRecordListData: LiveData<List<MockAbnormalRecords?>?> =
        _abnormalRecordListData

    private val _todoTaskGroupListData = MutableLiveData<List<TaskGroupData>>(listOf())
    val todoTaskGroupListData: LiveData<List<TaskGroupData>> = _todoTaskGroupListData.map {
        it.take(5)
    }

    val todoTaskGroupListSize: LiveData<String> = _todoTaskGroupListData.map {
        if (it.size > 5) return@map "5+" else it.size.toString()
    }

    private val _reliefTaskGroupListData = MutableLiveData<List<TaskGroupData>>(listOf())
    val reliefTaskGroupListData: LiveData<List<TaskGroupData>> =
        _reliefTaskGroupListData

    private val _spotPatrolUnDoneTaskGroupListData = MutableLiveData<List<TaskGroupData>>(listOf())
    val spotPatrolUnDoneTaskGroupListData: LiveData<List<TaskGroupData>> =
        _spotPatrolUnDoneTaskGroupListData

    private val _spotPatrolTimeOutTaskGroupListData = MutableLiveData<List<TaskGroupData>>(listOf())
    val spotPatrolTimeOutTaskGroupListData: LiveData<List<TaskGroupData>> =
        _spotPatrolTimeOutTaskGroupListData

    private val _spotPatrolDoneTaskGroupListData = MutableLiveData<List<TaskGroupData>>(listOf())
    val spotPatrolDoneTaskGroupListData: LiveData<List<TaskGroupData>> =
        _spotPatrolDoneTaskGroupListData

    private val _getTaskGroupListDataResult = MutableLiveData<ApiResult?>(null)
    val getTaskGroupListDataResult: LiveData<ApiResult?> = _getTaskGroupListDataResult

    private val _currentTaskGroupDetailData = MutableLiveData<TaskGroupData?>(null)
    val currentTaskGroupDetailData: LiveData<TaskGroupData?> = _currentTaskGroupDetailData

    private val _getTaskGroupDetailDataResult = MutableLiveData<ApiResult?>(null)
    val getTaskGroupDetailDataResult: LiveData<ApiResult?> = _getTaskGroupDetailDataResult

    private var taskGroupListOffset = 1

    private val _currentTaskDetailData = MutableLiveData<TaskData?>(null)
    val currentTaskDetailData: LiveData<TaskData?> = _currentTaskDetailData

    private val _getTaskDetailDataResult = MutableLiveData<ApiResult?>(null)
    val getTaskDetailDataResult: LiveData<ApiResult?> = _getTaskDetailDataResult

    private val _updateTaskDetailDataResult = MutableLiveData<ApiResult?>(null)
    val updateTaskDetailDataResult: LiveData<ApiResult?> = _updateTaskDetailDataResult

    private val _currentSpotDetectorData = MutableLiveData<SpotDetectorData?>(null)
    val currentSpotDetectorData: LiveData<SpotDetectorData?> = _currentSpotDetectorData

    private val _getAbnormalRecordsResult = MutableLiveData<ApiResult?>(null)
    val getAbnormalRecordsResult: LiveData<ApiResult?> = _getAbnormalRecordsResult

    private var _selectedExecutors: Set<SelectItem>? = null
    val selectedExecutors get() = _selectedExecutors

    private var _abnormalMediaDataMap = mutableMapOf<String, MutableSet<AbnormalOssData>>()
    val abnormalMediaDataMap get() = _abnormalMediaDataMap

    private val _getTaskDeviceBeaconsDataResult = MutableLiveData<ApiResult?>(null)
    val getTaskDeviceBeaconsDataResult: LiveData<ApiResult?> = _getTaskDeviceBeaconsDataResult

    private val _currentTaskDeviceBeaconsData = MutableLiveData<List<String>?>(null)
    val currentTaskDeviceBeaconsData: LiveData<List<String>?> = _currentTaskDeviceBeaconsData

    fun getAbnormalRecords() {
        viewModelScope.launch {
            try {
                val res = NetworkApi.getAbnormalRecords()
                Log.d(TAG, "res: $res")
                _getAbnormalRecordsResult.value = ApiResult(ApiState.DONE, null)
                _abnormalRecordListData.value = res.getOrNull()?.body()?.data
            } catch (e: Exception) {
                Log.e(TAG, "error: $e")
                _getAbnormalRecordsResult.value = ApiResult(ApiState.ERROR, e.message)
            }
        }
    }

    suspend fun getTaskGroupListData(
        isOffline: Boolean,
        type: TaskGroupType,
        status: List<TaskStatus>?,
        taskGroupStatus: TaskGroupStatus?,
        offset: Int = 1,
        limit: Int = DEFAULT_PAGE_LIMIT,
    ): Boolean {
        _getTaskGroupListDataResult.value = ApiResult(ApiState.LOADING, null)
        val res = SpcTaskRepository.getInstance().getSpcTask(
            isOffline,
            offset,
            limit,
            TASK_GROUP_LIST_QUERY_MAP[type],
            status,
            taskGroupStatus
        )
        Log.d(TAG, "res: $res")
        val e = res.exceptionOrNull()
        if (e != null) {
            Log.e(TAG, "Get $type group list data error: $e")
            _getTaskGroupListDataResult.value = ApiResult(ApiState.ERROR, e.message)
            return false
        }
        val resData = res.getOrNull()?.body()?.data?.data ?: listOf()
        val append = offset != 1
        when (type) {
            TaskGroupType.ALL -> {
                val oldData = todoTaskGroupListData.value
                _todoTaskGroupListData.value = if (append) oldData!!.plus(resData) else resData
            }
            TaskGroupType.RELIEF -> {
                val oldData = reliefTaskGroupListData.value
                _reliefTaskGroupListData.value =
                    if (append) oldData!!.plus(resData) else resData
            }
            TaskGroupType.SPOT_PATROL -> {
                when (status) {
                    TASK_GROUP_LIST_STATUS_QUERY_MAP[TaskGroupStatus.UN_DONE] -> {
                        val oldData = spotPatrolUnDoneTaskGroupListData.value ?: mutableListOf()
                        _spotPatrolUnDoneTaskGroupListData.value =
                            if (append) oldData.plus(resData) else resData
                    }
                    TASK_GROUP_LIST_STATUS_QUERY_MAP[TaskGroupStatus.TIMEOUT] -> {
                        val oldData =
                            spotPatrolTimeOutTaskGroupListData.value ?: mutableListOf()
                        _spotPatrolTimeOutTaskGroupListData.value =
                            if (append) oldData.plus(resData) else resData
                    }
                    TASK_GROUP_LIST_STATUS_QUERY_MAP[TaskGroupStatus.DONE] -> {
                        val oldData = spotPatrolDoneTaskGroupListData.value ?: mutableListOf()
                        _spotPatrolDoneTaskGroupListData.value =
                            if (append) oldData.plus(resData) else resData
                    }
                }
            }
        }
        _getTaskGroupListDataResult.value = ApiResult(ApiState.DONE, null)
        return resData.size < limit
    }

    fun getTaskGroupDetailData(isOnline: Boolean, taskGroupId: String) {
        if (getTaskGroupDetailDataResult.value?.state == ApiState.LOADING) {
            return
        }
        _getTaskGroupDetailDataResult.value = ApiResult(ApiState.LOADING, null)
        viewModelScope.launch {
            val res = SpcTaskRepository.getInstance()
                .getTaskGroupDetail(isOnline = isOnline, taskGroupId = taskGroupId)
            Log.d(TAG, "res: $res")
            val e = res.exceptionOrNull()
            if (e != null) {
                Log.e(TAG, "Get $taskGroupId data error: $e")
                _getTaskGroupDetailDataResult.value = ApiResult(ApiState.ERROR, e.message)
                return@launch
            }
            val resData = res.getOrNull()?.body()?.data ?: currentTaskGroupDetailData.value
            _getTaskGroupDetailDataResult.value = ApiResult(ApiState.DONE, null)
            _currentTaskGroupDetailData.value = resData
        }
    }

    fun setCurrentTaskGroupDetailData(tgDetailData: TaskGroupData?) {
        _currentTaskGroupDetailData.value = tgDetailData
    }

    fun getTaskDetailData(isOnline: Boolean, taskGroupId: String, taskId: Long) {
        _getTaskDetailDataResult.value = ApiResult(ApiState.LOADING, null)
        viewModelScope.launch {
            val res =
                SpcTaskRepository.getInstance().getTaskDetail(isOnline, taskGroupId, taskId)
            Log.d(TAG, "res: $res")
            val e = res.exceptionOrNull()
            if (e != null) {
                Log.e(TAG, "Get $taskId detail data error: $e")
                _getTaskDetailDataResult.value = ApiResult(ApiState.ERROR, e.message)
                return@launch
            }
            _currentTaskDetailData.value = res.getOrNull()?.body()?.data
            _getTaskDetailDataResult.value = ApiResult(ApiState.DONE, null)
        }
    }

    fun setCurrentTaskDetailData(taskDetailData: TaskData?) {
        _currentTaskDetailData.value = taskDetailData
    }

    fun updateTaskInfo(
        isOnline: Boolean,
        taskInfoList: List<TaskData>,
        needToUpdateGroupData: Boolean = false
    ) {
        _updateTaskDetailDataResult.value = ApiResult(ApiState.LOADING)
        viewModelScope.launch {
            val errorResultList = mutableListOf<ApiResult>()
            taskInfoList.forEach {
                val res = SpcTaskRepository.getInstance().updateTask(isOnline, it)
                val e = res.exceptionOrNull()
                if (e != null) {
//                    Log.e(TAG, "Update ${it.taskId} detail data error: $e")
                    errorResultList.add(ApiResult(ApiState.ERROR, it.taskId.toString()))
                } else {
                    SpcTaskRepository.getInstance().updateTaskGroupStatus(
                        it.groupID!!
                    )
                }
            }
            if (errorResultList.isEmpty()) {
                _updateTaskDetailDataResult.value = ApiResult(ApiState.DONE)
                val taskGroupId = currentTaskGroupDetailData.value?.groupID
                if (needToUpdateGroupData && taskGroupId != null) {
                    getTaskGroupDetailData(
                        isOnline,
                        taskGroupId
                    )
                }
                if (!needToUpdateGroupData && taskInfoList.isNotEmpty()) {
                    _currentTaskDetailData.value = taskInfoList[0]
                }
            } else {
                _updateTaskDetailDataResult.value =
                    ApiResult(ApiState.ERROR, "任务${errorResultList.map { it.message }}更新失败！")
            }
        }
    }

    fun setSelectedExecutors(selectedItemList: Set<SelectItem>?) {
        _selectedExecutors = selectedItemList
    }

    fun addAbnormalMedia(id: String, media: AbnormalOssData) {
        if (abnormalMediaDataMap[id].isNullOrEmpty()) {
            _abnormalMediaDataMap[id] = mutableSetOf()
        }
        _abnormalMediaDataMap[id]!!.add(media)
    }

    fun removeAbnormalMedia(id: String, media: AbnormalOssData) {
        if (abnormalMediaDataMap[id].isNullOrEmpty()) {
            return
        }
        _abnormalMediaDataMap[id]!!.removeIf {
            media.localUrl.split("/")?.let { it1 -> it.localUrl.contains(it1.last(), true) }
                ?: false
        }
    }

    fun clearAbnormalMedia() {
        _abnormalMediaDataMap = mutableMapOf()
    }

    fun setCurrentSpotDetectorData(spotDetectorData: SpotDetectorData?) {
        _currentSpotDetectorData.value = spotDetectorData
    }

    fun getDeviceBeacons(bleBeacons: List<String>?) {
        _getTaskDeviceBeaconsDataResult.value = ApiResult(ApiState.LOADING, null)
        _currentTaskDeviceBeaconsData.value = null
        _currentTaskDeviceBeaconsData.value = bleBeacons
    }

    fun clearApiResults() {
        _updateTaskDetailDataResult.value = null
        _getTaskGroupDetailDataResult.value = null
    }

    suspend fun downloadOfflineSpcTasks() {
        TASK_GROUP_LIST_QUERY_MAP[TaskGroupType.SPOT_PATROL]?.let {
            val timeStampOfLast2Days: Long = System.currentTimeMillis() / 1000 - 2 * 24 * 60 * 60
            val timeStampOfLast1Days: Long = System.currentTimeMillis() / 1000 - 1 * 24 * 60 * 60
            TASK_GROUP_LIST_STATUS_QUERY_MAP[TaskGroupStatus.UN_DONE]?.let { it1 ->
                SpcTaskRepository.getInstance().downloadOfflineSpcTasks(
                    it, it1, timeStampOfLast1Days
                )
            }

            TASK_GROUP_LIST_STATUS_QUERY_MAP[TaskGroupStatus.TIMEOUT]?.let { it1 ->
                SpcTaskRepository.getInstance().downloadOfflineSpcTasks(
                    it, it1, timeStampOfLast2Days
                )
            }
        }
    }

    companion object {
        private const val TAG = "SpotCheckViewModel"
        private const val DEFAULT_PAGE_LIMIT = 10
        private val TASK_GROUP_LIST_QUERY_MAP = mapOf(
            TaskGroupType.ALL to listOf(PlanType.RELIEF, PlanType.SPOT_PATROL),
            TaskGroupType.RELIEF to listOf(PlanType.RELIEF),
            TaskGroupType.SPOT_PATROL to listOf(PlanType.SPOT_PATROL),
        )
        val TASK_GROUP_LIST_STATUS_QUERY_MAP = mapOf(
            TaskGroupStatus.UN_DONE to listOf(TaskStatus.UN_START, TaskStatus.DOING),
            TaskGroupStatus.TIMEOUT to listOf(TaskStatus.TIMEOUT),
            TaskGroupStatus.DONE to listOf(TaskStatus.DONE, TaskStatus.TIMEOUT_DONE),
            TaskGroupStatus.TODO to listOf(TaskStatus.TIMEOUT, TaskStatus.DOING),
        )

        @JvmStatic
        fun hasTaskGroupNotDone(status: TaskStatus?): Boolean {
            return (status != TaskStatus.DONE && status != TaskStatus.TIMEOUT_DONE)
        }

        @JvmStatic
        fun isTaskSuffixVisible(
            statusIndicatorNotVisible: Boolean,
            checkboxVisible: Boolean
        ): Boolean {
            return if (checkboxVisible) {
                false
            } else {
                !statusIndicatorNotVisible
            }
        }

        @JvmStatic
        fun parseExecutorsString(executors: List<SelectItem>?): String? {
            return executors?.joinToString("、") { it.name }
        }
    }
}

class SpotCheckViewModelFactory :
    ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(SpotCheckViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return SpotCheckViewModel() as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}